home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK1.toast / Development Kits (Disc 1) / Open Transport / Sample Code / DLPI / OT DLPI Sample1.0B7 / Common Source / DLPIRoutines.c next >
Encoding:
Text File  |  1995-09-11  |  66.3 KB  |  2,137 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DLPIRoutines.c
  3.  
  4.     Contains:    This file contains the routine(s) to handle the DLPI calls from the
  5.                 client.  This file is very hardware independent.
  6.  
  7.     Written by:    
  8.  
  9.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.  
  14.     To Do:
  15. */
  16.  
  17. //-----------------------------------------------------------------------------------------
  18. //    Include files
  19. //-----------------------------------------------------------------------------------------
  20.  
  21. #include <OpenTptModule.h>            // Open Transport files
  22. #include <OpenTptDevLinks.h>
  23. #include <OpenTptLinks.h>
  24. #include <stropts.h>
  25. #include <dlpi.h>
  26.  
  27. #include <OSUtils.h>                // System files
  28. #include <Kernel.h>
  29. #include <DriverServices.h>
  30. #include <NameRegistry.h>
  31. #include <Interrupts.h>
  32.  
  33.  
  34. #include "EntryPoints.h"            // our files
  35. #include "DLPIRoutines.h"
  36. #include "HWSpecific.h"
  37.  
  38. //-----------------------------------------------------------------------------------------
  39. // Global variable for the entire CFM
  40. //-----------------------------------------------------------------------------------------
  41.  
  42. extern    DLPIPrivateData *gDLPIPrivateData;        // Declared in EntryPoints.c
  43.  
  44. //-----------------------------------------------------------------------------------------
  45. //    Description:
  46. //        A message block is passed to this routine, the routine determines if the message
  47. //        block can handled a certain size of data.  The reuse algorithm is done in this
  48. //        order:
  49. //    
  50. //            1. Reuse M_(PC)PROTO if available.
  51. //            2. Try to prepend header to first data block.
  52. //            3. Allocate a new message block to hold the header.
  53. //
  54. //    Input:
  55. //        mp - attempt to reuse the message block for a new message
  56. //        dataSizeNeeded - indicates the size of the new message needed
  57. //
  58. //    Output:
  59. //        message block pointer - to a newly allocate message block or the original mb
  60. //
  61. //-----------------------------------------------------------------------------------------
  62. mblk_t *ReuseMessageBlock(mblk_t *mp,UInt16 dataSizeNeeded)
  63. {
  64. mblk_t         *nmp;
  65.  
  66. if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim -  mp->b_datap->db_base) >= dataSizeNeeded)) 
  67.     {
  68.     mp->b_datap->db_type = M_DATA;
  69.     mp->b_rptr = mp->b_datap->db_base;
  70.     mp->b_wptr = mp->b_datap->db_base + dataSizeNeeded;
  71.     } 
  72. else 
  73.     {
  74.     nmp = mp->b_cont;                 // grab the M_DATA blocks
  75.     mp->b_cont = NULL;                 // detach the M_(PC)PROTO
  76.     freemsg(mp);                    // free the M_(PC)PROTO
  77.     mp = nmp;                        // point to the M_DATA blocks
  78.  
  79.         // try to get space on the first M_DATA block
  80.     if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= dataSizeNeeded)) 
  81.         mp->b_rptr -= dataSizeNeeded;
  82.     else 
  83.         {
  84.         if ((nmp = allocb(dataSizeNeeded, BPRI_HI)) == NULL)     // try to allocate a new message
  85.             {    // could not get a new message block so lets forget about the message altogether
  86.             freemsg(mp);             // free the original M_DATA portion of the message
  87.             mp = NULL;                 // indicates the reuse failed
  88.             }
  89.         else     
  90.             {
  91.             nmp->b_cont = mp;        // attach the new message block as the head
  92.             nmp->b_wptr += dataSizeNeeded;
  93.             mp = nmp;                 
  94.             } 
  95.         }
  96.     }
  97.  
  98. return mp;
  99. }
  100.  
  101. //-----------------------------------------------------------------------------------------
  102. //    Description:
  103. //        This routine builds a header for a packet that will be transmitted.  The passed
  104. //        in message (mp) has the header info in the first message block and then
  105. //        data in the following message blocks.  This routine uses the destination address
  106. //        info in the first message block to construct an Ethernet header which includes
  107. //        the dest, source (0, till sending packet), protocol/length (depends on the type
  108. //        of packet), and possible 802.2 sap and snap.  This header
  109. //        will contain the source, destination, type/length, and SAP/SNAP components.  The
  110. //        header that is built can be used for a packet header or a fast path header.
  111. //
  112. //    Input:
  113. //        theStream - the stream originating the packet
  114. //        mp - message block that contains info (source)
  115. //        forFastPathOnly - this flag determines if this is for the Mentat fastpath or
  116. //            a real packet header
  117. //
  118. //    Output:
  119. //        returns a message block that contains a formed packet header
  120. //
  121. //-----------------------------------------------------------------------------------------
  122. mblk_t *BuildTxPacketHeader(DLPIStream *theStream, mblk_t *mp, Boolean forFastPathOnly)
  123. {
  124.  
  125. UInt16                             hdrsize, datasize, dlsap;
  126. struct T8022FullPacketHeader     *packetHeader;
  127. UInt8                             *snapStart;
  128. UInt16                             proto,packetType;
  129. UInt8                             ctrl, responseFlag = 0;
  130. UInt8                             destAddrCopy[kMaxBoundAddrLength], *destAddrOrig, *reqStart;
  131. UInt32                            destAddrLen;
  132.  
  133. reqStart = mp->b_rptr;
  134.  
  135. switch (((union DL_primitives *)(reqStart))->dl_primitive)
  136.     {
  137.     case DL_UNITDATA_REQ:
  138.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_offset;
  139.         destAddrLen = ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_length;
  140.         ctrl = 0x03;
  141.         break;
  142.         
  143.     case DL_TEST_REQ:
  144.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_test_req_t*)reqStart)->dl_dest_addr_offset;
  145.         destAddrLen = ((dl_test_req_t*)reqStart)->dl_dest_addr_length;
  146.         ctrl = (((dl_test_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
  147.         break;
  148.         
  149.     case DL_XID_REQ:
  150.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_xid_req_t*)reqStart)->dl_dest_addr_offset;
  151.         destAddrLen = ((dl_xid_req_t*)reqStart)->dl_dest_addr_length;
  152.         ctrl = (((dl_xid_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
  153.         break;
  154.         
  155.     case DL_TEST_RES:
  156.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_test_res_t*)reqStart)->dl_dest_addr_offset;
  157.         destAddrLen = ((dl_test_res_t*)reqStart)->dl_dest_addr_length;
  158.         ctrl = (((dl_test_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
  159.         responseFlag = 1;
  160.         break;
  161.         
  162.     case DL_XID_RES:
  163.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_xid_res_t*)reqStart)->dl_dest_addr_offset;
  164.         destAddrLen = ((dl_xid_res_t*)reqStart)->dl_dest_addr_length;
  165.         ctrl = (((dl_xid_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
  166.         responseFlag = 1;
  167.         break;
  168.     default:
  169.         freemsg(mp);
  170.         return NULL;
  171.         break;
  172.     }
  173.  
  174. switch(destAddrLen)
  175.     {
  176.     case kEnetPhysicalAddressLength:    
  177.         dlsap = theStream->dlsap;
  178.         break;
  179.     case kEnetAndSAPAddressLength:    
  180.         dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
  181.         break;
  182.     case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength:    // snap sap
  183.         dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
  184.         break;
  185.     default:
  186.         dlsap = theStream->dlsap;
  187.         break;
  188.     }
  189.     
  190. datasize = msgdsize(mp);    // this does not include header info    
  191.     
  192. packetType = ClassifyPacketType(theStream->dlsap,dlsap);
  193.  
  194. switch(packetType)
  195.     {
  196.     case kPktDIX:
  197.         hdrsize = kEnetPacketHeaderLength; 
  198.         proto = dlsap;
  199.         break;
  200.     case kPkt8022SAP:
  201.         hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  202.         if (forFastPathOnly)
  203.             proto = 0;
  204.         else
  205.             proto = (datasize + k8022BasicHeaderLength);
  206.         break;
  207.     case kPkt8022SNAP:
  208.         hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
  209.         if (forFastPathOnly)
  210.             proto = 0;        
  211.         else
  212.             proto = datasize + k8022SNAPHeaderLength;
  213.         break;
  214.     case kPktIPX:
  215.         hdrsize = kEnetPacketHeaderLength;
  216.         if (forFastPathOnly)
  217.             proto = 0;
  218.         else
  219.             proto = datasize;        
  220.         break;
  221.     default:
  222.         hdrsize = kEnetPacketHeaderLength; 
  223.         proto = dlsap;
  224.         break;
  225.     }
  226.     
  227.     // we need to copy the dest address info in the message before we can reuse it
  228. bcopy(destAddrOrig, destAddrCopy, destAddrLen);
  229.     
  230. if ((mp = ReuseMessageBlock(mp,hdrsize)) == NULL)
  231.     return NULL;
  232.  
  233. packetHeader = (struct T8022FullPacketHeader *)mp->b_rptr;
  234.  
  235. packetHeader->fEnetPart.fProto = proto;        // set proto or length
  236.  
  237. switch(packetType)
  238.     {
  239.     case kPkt8022SAP:
  240.         packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
  241.         packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
  242.         packetHeader->f8022Part.fCtrl = ctrl;
  243.         break;
  244.     case kPkt8022SNAP:
  245.         packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
  246.         packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
  247.         packetHeader->f8022Part.fCtrl = ctrl;
  248.         if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength)
  249.             snapStart = destAddrCopy + kEnetAndSAPAddressLength;
  250.         else
  251.             snapStart = theStream->snap;
  252.         OTCopy8022SNAP(snapStart,packetHeader->f8022Part.fSNAP);
  253.         break;
  254.     default:
  255.         break;
  256.     }
  257.  
  258. OTCopy48BitAddress(destAddrCopy,packetHeader->fEnetPart.fDestAddr);
  259.  
  260. return(mp);
  261. }
  262.  
  263. //-----------------------------------------------------------------------------------------
  264. //    Description:
  265. //        This routine checks if the address is a multicast address, broadcast, or standard
  266. //        address.
  267. //
  268. //    Input:
  269. //        addr - pointer to an array of 6 bytes that is an ethernet address 
  270. //
  271. //    Output:
  272. //        return type of address
  273. //
  274. //-----------------------------------------------------------------------------------------
  275. SInt32 GetAddressType(UInt8 *addr) 
  276. {
  277.  
  278. if (addr[0] & 1)     // is address multicast or broadcast
  279.     {
  280.     if (OTIs48BitBroadcastAddress(addr))
  281.         return keaBroadcast;
  282.     else
  283.         return keaMulticast;
  284.     } 
  285. else
  286.     return keaStandardAddress;
  287. }
  288.  
  289. //-----------------------------------------------------------------------------------------
  290. //    Description:
  291. //        This routine handles the binding of a stream.  The stream must not be in the 
  292. //        bind state when this call is made.  In other words, a stream can only be bound
  293. //        once.  The call is ack'd by doing sending a message block with a bind ack
  294. //        message.
  295. //
  296. //    Input:
  297. //        theStream - the stream that the client wants to bind
  298. //        mp - message block that contains the parameters for the bind call
  299. //
  300. //    Output:
  301. //        returns the status of the call
  302. //
  303. //-----------------------------------------------------------------------------------------
  304. SInt32 BindTheStream(DLPIStream *theStream, mblk_t *mp)
  305. {
  306. dl_bind_req_t     *req = (dl_bind_req_t *)mp->b_rptr;
  307. UInt16             dlsap = (UInt16)req->dl_sap;
  308. DLPIStream         *tempStream;
  309. mblk_t             *ack_mp;
  310. SInt32             i;
  311.  
  312. if (req->dl_service_mode != DL_CLDLS) 
  313.     return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0));
  314.  
  315. if (theStream->dlpiState != DL_UNBOUND) 
  316.     return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_OUTSTATE, 0));
  317.  
  318.     // don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF)
  319.     //  because it looks like IPX
  320. if ((dlsap < kMax8022SAP) && (dlsap & 1))    
  321.     return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
  322.  
  323. if (ClassifyPacketType(dlsap,dlsap) == kPktUnknown)
  324.     return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
  325.  
  326. if ((ack_mp = BuildBindAck(theStream, dlsap)) == NULL)
  327.     return (kdlpiRETRY);
  328.  
  329. for (i = 0; i < kGroupSAPMapSize; i++)
  330.     theStream->group_sap[i] = 0;
  331.     
  332. if (dlsap <= kMax8022SAP)
  333.     SetGroupSAP(theStream, k8022GlobalSAP);    
  334.  
  335. if (req->dl_xidtest_flg & DL_AUTO_XID)
  336.     theStream->streamFlags |= kAutoXID;    
  337.  
  338. if (req->dl_xidtest_flg & DL_AUTO_TEST)
  339.     theStream->streamFlags |= kAutoTest;    
  340.  
  341. freemsg(mp);
  342.  
  343. theStream->dlpiState = DL_IDLE;
  344. theStream->dlsap = dlsap;
  345. theStream->streamFlags &= ~kSnapStream;
  346. putnext(theStream->readQueue, ack_mp);     // and reply with the ACK
  347. return (kdlpiDONE);
  348. }
  349.  
  350. //-----------------------------------------------------------------------------------------
  351. //    Description:
  352. //        This routine builds the bind ack message block.
  353. //
  354. //    Input:
  355. //        theStream - the stream to send the bind ack to
  356. //        dlsap - the sap for the current stream
  357. //
  358. //    Output:
  359. //        returns a message block that contains the bind ack message
  360. //
  361. //-----------------------------------------------------------------------------------------
  362. mblk_t *BuildBindAck(DLPIStream *theStream, UInt16 dlsap)
  363. {
  364. dl_bind_ack_t    *ackp;
  365. mblk_t             *mp;
  366. T8022AddressStruct    *addrInfo;
  367.  
  368. if ((mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) 
  369.     {
  370.     DoWriteScheduler(theStream, sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength);
  371.     return(NULL);
  372.     }
  373.     
  374. mp->b_datap->db_type = M_PCPROTO;
  375. ackp = (dl_bind_ack_t *)mp->b_rptr;
  376. ackp->dl_primitive = DL_BIND_ACK;
  377. ackp->dl_sap = dlsap;
  378. ackp->dl_addr_length = kEnetAndSAPAddressLength;        
  379. ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
  380. ackp->dl_max_conind = 0;
  381. ackp->dl_xidtest_flg = 0;
  382.  
  383. addrInfo = (T8022AddressStruct *)(mp->b_rptr + sizeof(dl_bind_ack_t));
  384. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,addrInfo->fHWAddr);
  385. addrInfo->fSAP = dlsap;
  386.  
  387.     // must move b_wptr past the address info data
  388. mp->b_wptr = mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength;
  389.     
  390. return(mp);
  391. }
  392.  
  393.  
  394. //-----------------------------------------------------------------------------------------
  395. //    Description:
  396. //         This routine builds a header from a packet that was received.  The header
  397. //        includes the destination and source address.  The sap and snap are also
  398. //        copied.
  399. //
  400. //                        Ethernet Header
  401. //                    +-----------------------+
  402. //      packetHeader    |      dest addr        |    6 bytes
  403. //                    +-----------------------+
  404. //                    |      src addr         |    6 bytes
  405. //                    +-----------------------+
  406. //                    |      type/protocol    |    2 bytes
  407. //                    +-----------------------+
  408. //                    |      dest SAP         |    1 bytes        802.2 and IPX only
  409. //                    +-----------------------+
  410. //                    |      src SAP          |    1 bytes        802.2 and IPX only
  411. //                    +-----------------------+
  412. //                    |      control          |    1 bytes        802.2 only
  413. //                    +-----------------------+
  414. //                    |      SNAP             |    5 bytes        802.2 and 0xAA dest sap
  415. //                    +-----------------------+
  416. //
  417. //        The Ethernet header information must be moved into a memory block with
  418. //        the following format:
  419. //
  420. //                        Indication Header
  421. //                    +-----------------------+
  422. //        destAddr    |      dest addr        |    6 - 13 bytes 
  423. //                    +-----------------------+
  424. //        srcAddr        |      src addr         |    6 - 13 bytes
  425. //                    +-----------------------+
  426. //    
  427. //        The Indication header destination and source address fields can contain from
  428. //        6 to 13 bytes.  The minimum is the Ethernet addresses from the Ethernet header.
  429. //        They could also contain the sap and snap information:
  430. //
  431. //                    dest or src addr format
  432. //                    +-----------------------+
  433. //                    |     Ethernet addr     |    6 bytes 
  434. //                    +-----------------------+
  435. //                    |         SAP             |    2 bytes
  436. //                    +-----------------------+
  437. //                    |         SNAP             |    5 bytes
  438. //                    +-----------------------+
  439. //
  440. //    Input:
  441. //        mp - message block that contains the info for building a test message
  442. //        dlsap_length - the number of bytes in the mp message block 
  443. //
  444. //    Output:
  445. //        returns a message block that contains an the test message
  446. //
  447. //-----------------------------------------------------------------------------------------
  448. void BuildRxDestSrcHeader(T8022FullPacketHeader *packetHeader,
  449.                             T8022AddressStruct *destAddr,
  450.                             T8022AddressStruct *srcAddr,
  451.                             UInt32 dlsap_length)
  452.                             
  453. {
  454.  
  455. OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr,destAddr->fHWAddr);
  456. OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr,srcAddr->fHWAddr);
  457.  
  458.     //    Pull 8022 SAP from packet, if bytes remain in the dlsap_length.
  459.  
  460. switch (dlsap_length) 
  461.     {
  462.     case kEnetAndSAPAddressLength + k8022SNAPLength:
  463.         OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,destAddr->fSNAP);
  464.         OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,srcAddr->fSNAP);
  465.                                         // no break because we want to do the sap also
  466.     case kEnetAndSAPAddressLength:
  467.         destAddr->fSAP = packetHeader->f8022Part.fDSAP;
  468.         srcAddr->fSAP = packetHeader->f8022Part.fSSAP;
  469.         break;
  470.         
  471.     default:        // for Ethernet address do nothing
  472.         break;
  473.     }
  474.     
  475. }
  476.  
  477. //-----------------------------------------------------------------------------------------
  478. //    Description:
  479. //        This routines builds the message block for the Indication message. The appropriate
  480. //        information is set in the message.  The destination and source dlsaps are put
  481. //        into the M_PROTO block.  These dlsaps could be classic ethernet, 802.2, or IPX.
  482. //        The "data" portion of the message only contains pure data.  For 802.2 this
  483. //        is everything past the snap or sap if there is no snap.  For classic ethernet
  484. //        this is everything past the protocol type.  For IPX this includes FF FF 03 +
  485. //        the data.
  486. //
  487. //    Input:
  488. //        mp - message block that contains the info for building a indication message
  489. //        dlsap_length - the number of bytes in the mp message block 
  490. //
  491. //    Output:
  492. //        returns a message block that contains an the Indication message
  493. //
  494. //-----------------------------------------------------------------------------------------
  495. void BuildUnitDataIndication(DLPIStream *theStream, mblk_t *mp, 
  496.         UInt16 destAddrLength, UInt16 headerHideLength)
  497. {
  498. mblk_t                 *nmp;
  499. dl_unitdata_ind_t     *ind;
  500. SInt32                     addressType;
  501. T8022FullPacketHeader    *packetHeader;
  502. T8022AddressStruct        *srcAddr,*destAddr;
  503.  
  504.     //    Allocate the dl_unitdata_ind_t message, and fill it in.
  505. if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + (2 * destAddrLength), BPRI_HI)) == NULL)
  506.     {
  507.     freemsg(mp);
  508.     return;
  509.     }
  510.  
  511. nmp->b_datap->db_type = M_PROTO;
  512.     
  513. ind = (dl_unitdata_ind_t*)nmp->b_rptr;
  514. ind->dl_primitive = DL_UNITDATA_IND;
  515. ind->dl_dest_addr_length = destAddrLength;
  516. ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
  517. ind->dl_src_addr_length = destAddrLength;
  518. ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + destAddrLength;
  519.  
  520. addressType = GetAddressType(mp->b_rptr);
  521. if (addressType == keaStandardAddress)
  522.     ind->dl_group_address = 0;
  523. else
  524.     ind->dl_group_address = addressType;    // broadcast or multicast
  525.  
  526. nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + destAddrLength + destAddrLength);
  527.  
  528. packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
  529.  
  530. destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
  531. srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
  532.  
  533. BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
  534.  
  535. if (theStream->streamFlags & kReadRawPackets)    // a raw packet comming in
  536.     ind->dl_group_address |= keaRawPacketBit;    // marks packet as raw
  537. else
  538.     mp->b_rptr += headerHideLength;    // "hide" the ethernet and protocol header(s)
  539.     
  540. linkb(nmp, mp);        // append dlpi header to the packet data message block.
  541. putnext(theStream->readQueue, nmp);        // pass the message up the stream
  542. return;
  543.  
  544. }
  545.  
  546. //-----------------------------------------------------------------------------------------
  547. //    Description:
  548. //        Process M_DATA mblk_ts from the device (the lower half of the driver.
  549. //        This is the basic client stream service routine to prepend the right kind 
  550. //        of DLPI information to the raw data coming in off the wire.  The packet is
  551. //         then placed on the stream read queue for processing by our client.
  552. //
  553. //    Input:
  554. //        theStream - the stream that will receive this packet
  555. //        mp - the message block that contains the received packet
  556. //
  557. //    Output:
  558. //        no return value explicitly
  559. //
  560. //-----------------------------------------------------------------------------------------
  561. void HandleReceivedPacket(DLPIStream *theStream, mblk_t *mp, UInt16 packetType)
  562. {
  563. Boolean        isTest = kFalse;
  564. Boolean        isXID = kFalse;
  565. Boolean        isCommand = kTrue;
  566. UInt16        destAddrLength;
  567. UInt32        headerHideLength;
  568. UInt8        ctrl;
  569. mblk_t        *nmp;
  570. Boolean        is8022 = kFalse;
  571.  
  572. switch( packetType )
  573.     {
  574.     case kPktDIX:
  575.         destAddrLength = kEnetPhysicalAddressLength;
  576.         headerHideLength = kEnetPacketHeaderLength;
  577.         break;
  578.     case kPkt8022SAP:
  579.         destAddrLength = kEnetAndSAPAddressLength;
  580.         headerHideLength = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  581.         is8022 = kTrue;
  582.         break;
  583.     case kPkt8022SNAP:
  584.         destAddrLength = kEnetAndSAPAddressLength + k8022SNAPLength;
  585.         headerHideLength = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
  586.         is8022 = kTrue;
  587.         break;
  588.     case kPktIPX:
  589.         destAddrLength = kEnetPhysicalAddressLength;
  590.         headerHideLength = kEnetPacketHeaderLength;
  591.         break;
  592.     default:
  593.         break;
  594.     }
  595.  
  596. if (theStream->streamFlags & kReadRawPackets)    // raw packet comming in
  597.     {
  598.     BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
  599.     return;
  600.     }
  601.  
  602.  
  603. if (is8022)
  604.     {
  605.     ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
  606.     isTest = (ctrl & 0xEF) == 0xE3;
  607.     isXID = (ctrl & 0xEF) == 0xAF;
  608.     isCommand = (((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP & 1) == 0;
  609.  
  610.     if (isTest && isCommand && (theStream->streamFlags & kAutoTest)) 
  611.         {
  612.         DoTestResponse(theStream, mp);
  613.         return;
  614.         }
  615.  
  616.     if (isXID && isCommand && (theStream->streamFlags & kAutoXID)) 
  617.         {
  618.         DoXidResponse(theStream, mp);
  619.         return;
  620.         }
  621.     
  622.     if (isTest || isXID)    // indication (request) or confirmation (response, auto off)
  623.         {
  624.         BuildXidTestConfirmIndication(theStream, mp, destAddrLength, headerHideLength);
  625.         return;
  626.         }
  627.  
  628.     }
  629.  
  630.     // send packet up the stream
  631. BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
  632.  
  633. }
  634.  
  635. //-----------------------------------------------------------------------------------------
  636. //    Description:
  637. //        This routine is called because the callee wants to check if the passed in
  638. //        multicast ethernet address has already been registered with this stream.  A linked
  639. //        list of message blocks that contain 1 registered multicast address is kept on
  640. //        a per stream basis.  This routine call also be used to dequeue the mb that
  641. //        contains the already registered multicast address.
  642. //
  643. //    Input:
  644. //        multicastQueue - pointer to a queue header for the linked list of mb's
  645. //        reqaddr - ethernet multicast address to be checked against the linked list
  646. //        dequeueBlock - determines whether the mb containing the registered multicast 
  647. //            should be dequeued from the linked list
  648. //
  649. //    Output:
  650. //        returns null if no match is found, returns the mb if it is found
  651. //
  652. //-----------------------------------------------------------------------------------------
  653. mblk_t *IsAddressRegistered(QHdr *multicastQueue,UInt8 *reqaddr, Boolean dequeueBlock,
  654.     UInt16 interruptMask)
  655. {
  656. mblk_t    *mbWalker;
  657.  
  658.  
  659. ABCVendorDisableInterrupts(interruptMask);        
  660.  
  661. if ((mbWalker = (mblk_t *)multicastQueue->qHead) == NULL)
  662.     {
  663.     ABCVendorEnableInterrupts(interruptMask);
  664.     return NULL;
  665.     }
  666.  
  667. while (mbWalker) 
  668.     {
  669.     if (CheckAddressMatch((UInt8 *)mbWalker->b_rptr, reqaddr, kEnetPhysicalAddressLength)) 
  670.         {
  671.         if (dequeueBlock)
  672.             DequeueElement(multicastQueue,(QElem *)mbWalker, 0);
  673.         break;
  674.         }
  675.     else
  676.         mbWalker = mbWalker->b_next;    // check the next mb/address
  677.     }
  678.     
  679. ABCVendorEnableInterrupts(interruptMask);
  680.  
  681.  
  682. return mbWalker;
  683.  
  684. }
  685.  
  686. //-----------------------------------------------------------------------------------------
  687. //    Description:
  688. //        This routine handles removing a registered multicast address from the stream.
  689. //        First the address is checked to make sure it is a valid multicast address.
  690. //        Then the mc is checked to see if it has actually been registered.  If
  691. //        everything passes then an OK ack is sent to the client.  If not then an error
  692. //        ack is sent.
  693. //
  694. //    Input:
  695. //        theStream - the stream requesting the disable
  696. //        mp - message block containing the DL_DISABMULTI_REQ parameters
  697. //
  698. //    Output:
  699. //        returns status of the call
  700. //
  701. //-----------------------------------------------------------------------------------------
  702. SInt32 DoDisableMulticast(DLPIStream *theStream, mblk_t *mp) 
  703. {
  704. dl_disabmulti_req_t*     req = (dl_disabmulti_req_t*)mp->b_rptr;
  705. UInt8                     *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
  706. mblk_t                     *mc;
  707.  
  708. if (GetAddressType(reqaddr) != keaMulticast) 
  709.     {
  710.     DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
  711.     return (kdlpiDONE);
  712.     }
  713.     
  714.     // find address and dequeue if found
  715. if ((mc = IsAddressRegistered(&theStream->multicastQueue,reqaddr,kTrue,kRxInterrupts)) != NULL)    
  716.     {
  717.     freemsg(mc);
  718.     ABCVendorUnregisterMulticast(reqaddr);    // turn off multicast addr if no one is using it
  719.  
  720.     if (theStream->multicastQueue.qHead == NULL)
  721.         theStream->streamFlags &= ~kAcceptMulticasts;    // no longer check multicast packets
  722.         
  723.     DoOKAck(theStream, mp, DL_DISABMULTI_REQ);
  724.     return (kdlpiDONE);
  725.     }
  726.  
  727. DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
  728. return (kdlpiDONE);
  729. }
  730.  
  731. //-----------------------------------------------------------------------------------------
  732. //    Description:
  733. //        This routine handles the DL_ENABMULTI_REQ call to enable a multicast address
  734. //        for a certain stream.  The address is checked to make sure it is indeed a 
  735. //        multicast address.  Then a check is done to see if the address has already
  736. //        been registered.
  737. //
  738. //        If everything passes then an OK ack is sent to the client.  If not then an error
  739. //        ack is sent.
  740. //
  741. //    Input:
  742. //        theStream - the stream requesting the enable
  743. //        mp - message block containing the DL_ENABMULTI_REQ parameters
  744. //
  745. //    Output:
  746. //        returns status of the call
  747. //
  748. //-----------------------------------------------------------------------------------------
  749. SInt32 DoEnableMulticast(DLPIStream *theStream, mblk_t *mp) 
  750. {
  751.  
  752. dl_enabmulti_req_t*    req = (dl_enabmulti_req_t*)mp->b_rptr;
  753. UInt8                 *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
  754. mblk_t                 *mc;
  755. SInt32                 i;
  756.  
  757. if (GetAddressType(reqaddr) == keaMulticast)
  758.     {
  759.     if (IsAddressRegistered(&theStream->multicastQueue,reqaddr,kFalse,kRxInterrupts))    
  760.         {
  761.         DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
  762.         return (kdlpiDONE);
  763.         }
  764.         
  765.     if ((mc = allocb(kEnetPhysicalAddressLength, BPRI_HI)) == NULL) 
  766.         {
  767.         DoWriteScheduler(theStream, kEnetPhysicalAddressLength);
  768.         return(kdlpiRETRY);
  769.         }
  770.  
  771.     ABCVendorRegisterMulticast(reqaddr);
  772.         
  773.     for (i = 0; i < kEnetPhysicalAddressLength; i++)
  774.         *mc->b_wptr++ = *reqaddr++;
  775.  
  776.         // add new address to multicast list
  777.     EnqueueElement(&theStream->multicastQueue,(QElem *)mc,kBothTxRxInterrupts);    
  778.     
  779.     DoOKAck(theStream, mp, DL_ENABMULTI_REQ);
  780.     
  781.     theStream->streamFlags |= kAcceptMulticasts;    // on receive now check multicast packets
  782.     }
  783. else 
  784.     DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
  785.     
  786. return (kdlpiDONE);
  787. }
  788.  
  789. //-----------------------------------------------------------------------------------------
  790. //    Description:
  791. //        This routine is used to enable the write queue.
  792. //
  793. //    Input:
  794. //        p - the stream that contains the write queue that needs to be enabled
  795. //
  796. //    Output:
  797. //        NONE
  798. //
  799. //-----------------------------------------------------------------------------------------
  800. void EnableWriteQueue(long p)
  801. {
  802. DLPIStream *theStream = (DLPIStream *)p;
  803.  
  804. if (theStream->readQueue) 
  805.     {
  806.     theStream->idType = NULL;    // mark us as no event waiting 
  807.     qenable(WR(theStream->readQueue));
  808.     }
  809. }
  810.  
  811. //-----------------------------------------------------------------------------------------
  812. //    Description:
  813. //        This routine builds and sends (if possible) an error ack for a particular call
  814. //        made by a client.  If memory cannot be allocated for the ack message block
  815. //        then a scheduled event is queued.
  816. //
  817. //    Input:
  818. //        theStream - the stream to send the error ack to
  819. //        ack_mp - the message block to use for the ack
  820. //        prim - the primitive or call that caused the error ack
  821. //        err - error number to be placed in the error ack message block
  822. //        uerr - the unix error number
  823. //
  824. //    Output:
  825. //        returns status of the call
  826. //
  827. //-----------------------------------------------------------------------------------------
  828. SInt32 DoErrorAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 prim, UInt32 err, UInt32 uerr)
  829. {
  830. dl_error_ack_t *errp;
  831.  
  832. if (ack_mp == NULL) 
  833.     {
  834.     if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) 
  835.         {
  836.         DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
  837.         return(kdlpiRETRY);
  838.         }
  839.     } 
  840. else     // so we have a message block
  841.     {
  842.     if (ack_mp->b_datap->db_ref != 1)    // is anybody else using this message data
  843.         {
  844.         freemsg(ack_mp);
  845.         if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) 
  846.             {
  847.             DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
  848.             return(kdlpiRETRY);
  849.             }
  850.         } 
  851.     else    // we are the only ones using this message
  852.         {
  853.         ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
  854.         if (ack_mp->b_cont != NULL) 
  855.             {
  856.             freemsg(ack_mp->b_cont);
  857.             ack_mp->b_cont = NULL;
  858.             }
  859.         }
  860.     }
  861.     
  862. ack_mp->b_datap->db_type = M_PCPROTO;
  863. errp = (dl_error_ack_t *)ack_mp->b_wptr;
  864. errp->dl_primitive = DL_ERROR_ACK;
  865. errp->dl_error_primitive = prim;
  866. errp->dl_errno = err;
  867. errp->dl_unix_errno = uerr;
  868. ack_mp->b_wptr += sizeof(dl_error_ack_t);
  869. putnext(theStream->readQueue, ack_mp);
  870. return(kdlpiDONE);
  871. }
  872.  
  873. //-----------------------------------------------------------------------------------------
  874. //    Description:
  875. //        This routine checks if the stream has already been registered by a certain sap.
  876. //        The sap could also contain a snap.
  877. //
  878. //    Input:
  879. //        theStream - the stream used for checking the new sap
  880. //        sap - the sap plus possibly snap that is being checked to see if it is already
  881. //            registered
  882. //        len - the number of bytes valid in the sap
  883. //
  884. //    Output:
  885. //        returns kTrue if sap is already registered, returns kFalse if not registered
  886. //
  887. //-----------------------------------------------------------------------------------------
  888. SInt32 FindSnap(DLPIStream *theStream, UInt8 *sap, SInt32 len)
  889. {
  890. DLPIStream     *tempStream = (DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  891.  
  892. while (tempStream) 
  893.     {
  894.     if (tempStream->streamFlags & kSnapStream) 
  895.         {
  896.         if (CheckAddressMatch(sap, tempStream->snap, len))
  897.             return kTrue;
  898.         }
  899.     tempStream = tempStream->nextStream;
  900.     }
  901. return kFalse;        
  902. }
  903.  
  904. //-----------------------------------------------------------------------------------------
  905. //    Description:
  906. //        This routine classifies a packet into the different types of protocols.  For IPX
  907. //        we need both the source and destination SAPs to make a protocol determination.
  908. //
  909. //    Input:
  910. //        thePacket - a message block the contains the received packet
  911. //
  912. //    Output:
  913. //        returns type of packet
  914. //
  915. //-----------------------------------------------------------------------------------------
  916. UInt16 ClassifyPacketType(UInt16 primarySAP, UInt16 secondarySAP)
  917. {
  918.  
  919. if (primarySAP >= kMinDIXSAP)         
  920.     return kPktDIX;
  921.  
  922. if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP))
  923.     return kPktIPX;
  924.  
  925. if (primarySAP == kSNAPSAP)
  926.     return kPkt8022SNAP;
  927.  
  928. if (primarySAP <= k8022GlobalSAP)
  929.     return kPkt8022SAP;
  930.  
  931. return kPktUnknown;
  932. }
  933.  
  934. //-----------------------------------------------------------------------------------------
  935. //    Description:
  936. //        This routine extracts the sap information from the ethernet packet header.
  937. //
  938. //    Input:
  939. //        fullpkt - ptr to Ethernet packet header
  940. //        sourceSAP - return source sap here
  941. //        destSAP - return dest sap here
  942. //
  943. //    Output:
  944. //        NONE
  945. //
  946. //-----------------------------------------------------------------------------------------
  947. void ExtractSAPValues(T8022FullPacketHeader *fullpkt, UInt16 *sourceSAP, UInt16 *destSAP)
  948. {
  949.  
  950.  
  951. *destSAP = fullpkt->fEnetPart.fProto;
  952.  
  953. if (*destSAP >= kMinDIXSAP)        // classic ethernet
  954.     *sourceSAP = *destSAP;
  955. else
  956.     {
  957.     *destSAP = fullpkt->f8022Part.fDSAP;
  958.     *sourceSAP = fullpkt->f8022Part.fSSAP;
  959.     }
  960.  
  961. }
  962.  
  963. //-----------------------------------------------------------------------------------------
  964. //    Description:
  965. //        This routine checks each stream to see if it "wants" the packet.  In the loop
  966. //        each stream that wants the packet is placed in a linked list (queue).  After
  967. //        all the streams are examined then the packet is passed to each stream (while loop).  
  968. //        If more than 1 stream wants the packet then n-1 streams receive a dupmsg packet
  969. //        and the last stream receives the original.
  970. //
  971. //        In order to build the list we have to jump through some hoops so we don't have
  972. //        to allocate any memory.  In the DLPIStream struct a rxPacketLink follows
  973. //        the real link.  We use the rxPacketLink field to link the streams together.
  974. //        I should mention that the real link field keeps track of all the opened streams
  975. //        for this piece of hw.  So we build a list of streams that want the packet
  976. //        and then we walk the list and send the packet to each stream.  Since the
  977. //        rxPacketLink is not at the beginning of the DLPIStream structure we must
  978. //        subtract 4 from the value in the link to get back to the beginning of the 
  979. //        DLPIStream structure.
  980. //
  981. //        Now why do we jump through so many whoops?  Well we could just find a stream
  982. //        that wants the packet and then dupmsg to each stream.  After we exit the loop
  983. //        then just free the original message.  By doing all this fancy stuff we save
  984. //        doing the dupmsg for one stream, in fact if only 1 stream wants the packet
  985. //        then no duping is done.  So we save some memory and time by not duping if we
  986. //        don't have to.  Make sense?  Feel free to change it to the simpler method if
  987. //        you want.
  988. //        
  989. //    Input:
  990. //        theStream - the first stream in a list of streams that will be checked
  991. //        mp - a message block that contains the received packet
  992. //
  993. //    Output:
  994. //        NONE
  995. //
  996. //-----------------------------------------------------------------------------------------
  997. void FindStreamForReceivedPacket(DLPIStream *theStream, mblk_t *mp)
  998. {
  999. EnetPacketHeader         *pkt = (EnetPacketHeader *)mp->b_rptr;
  1000. T8022FullPacketHeader    *fullpkt;
  1001. Boolean                 isOurs;
  1002. UInt16                     packetType,sourceSAP,destSAP;
  1003. mblk_t                     *copy_of_mp = NULL;
  1004. SInt32                     destAddressType;
  1005. QHdr                    wantsPacketQueue;
  1006. DLPIStream                 *fakeStream;
  1007.  
  1008.     // init queue for storing streams that want the rx packet
  1009. wantsPacketQueue.qHead = NULL;        
  1010. wantsPacketQueue.qTail = NULL;
  1011.  
  1012. fullpkt = (T8022FullPacketHeader *)pkt;
  1013.  
  1014. ExtractSAPValues(fullpkt,&sourceSAP, &destSAP);
  1015.  
  1016. packetType = ClassifyPacketType(sourceSAP,destSAP);
  1017.             
  1018. destAddressType = GetAddressType(pkt->fDestAddr);
  1019.  
  1020. for (; theStream; theStream = theStream->nextStream) 
  1021.     {
  1022.     isOurs = kFalse;
  1023.     if (theStream->dlpiState == DL_UNBOUND)     // can't send to unbound streams
  1024.         continue;
  1025.         
  1026.         // does this stream want all 802.2 packets?
  1027.     if ((theStream->streamFlags & kAcceptAll8022Packets) && (destSAP <= 0xff))    
  1028.         {
  1029.         EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
  1030.         continue;
  1031.         }
  1032.     
  1033.     if (destSAP == theStream->dlsap) 
  1034.         {
  1035.         if (theStream->streamFlags & kSnapStream)  // check SNAPs if necessary 
  1036.             isOurs = CheckAddressMatch(fullpkt->f8022Part.fSNAP, theStream->snap, 
  1037.                 k8022SNAPLength);
  1038.         else            // no SNAP, found a match since saps match 
  1039.             isOurs = kTrue;
  1040.         
  1041.         } 
  1042.     else     // Check for an 802.3 Group/Global (odd) 
  1043.         {
  1044.         if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP))
  1045.             && (destSAP & 1) && TestGroupSAP(theStream, destSAP))
  1046.             isOurs = kTrue;
  1047.         }
  1048.     
  1049.     if (!isOurs)    // this stream does not want this packet
  1050.         continue;
  1051.  
  1052.         // if this is a multicast packet, see if it is destined for an address we
  1053.          // are interested in
  1054.     if (isOurs && (destAddressType == keaMulticast) && 
  1055.             (theStream->streamFlags & kAcceptMulticasts)) 
  1056.         {
  1057.         isOurs = kFalse;        // assume no match 
  1058.         if (IsAddressRegistered(&theStream->multicastQueue,pkt->fDestAddr,kFalse, kNoInterrupts))    
  1059.             isOurs = kTrue;
  1060.         }
  1061.         
  1062.         // add stream to our list if it can accept the packet 
  1063.     if (isOurs && canput(theStream->readQueue->q_next))
  1064.         EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
  1065.     }
  1066.  
  1067.  
  1068.     // once all the streams that want this packet have been put on the queue we need
  1069.     //  to go through the streams list, when multiple streams want the packet all
  1070.     //  the streams get a duplicate except for the last stream which gets the original
  1071.     //  this saves an extra duplicate
  1072.  
  1073. if (wantsPacketQueue.qHead == NULL)
  1074.     freemsg(mp);    // nobody wanted the message (packet)
  1075. else
  1076.     {    // 1 or more streams want this packet
  1077.     fakeStream = (DLPIStream *)wantsPacketQueue.qHead;
  1078.     theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
  1079.     while (theStream->rxPacketLink)
  1080.         {
  1081.         if ((copy_of_mp = dupmsg(mp)) != NULL)
  1082.             HandleReceivedPacket(theStream, copy_of_mp,packetType);
  1083.         fakeStream = theStream->rxPacketLink;
  1084.         theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
  1085.         }
  1086.     HandleReceivedPacket(theStream, mp,packetType);    // send original
  1087.     }
  1088.         
  1089. }
  1090.  
  1091. //-----------------------------------------------------------------------------------------
  1092. //    Description:
  1093. //         This routine handles the info primitive/call from the client.  The information is
  1094. //        collected from the DLPI and then placed in a message block that will be returned
  1095. //        to the client.
  1096. //
  1097. //    Input:
  1098. //        theStream - the stream from which the information is collected
  1099. //
  1100. //    Output:
  1101. //        returns status of the call
  1102. //
  1103. //-----------------------------------------------------------------------------------------
  1104. SInt32 DoGeneralInfo(DLPIStream *theStream)
  1105. {
  1106. dl_info_ack_t    *ackp;
  1107. mblk_t             *ack_mp;
  1108. UInt32             saplen = 0;
  1109. UInt32             addrlen = kEnetPhysicalAddressLength;
  1110. UInt32             bcastlen = kEnetPhysicalAddressLength;
  1111. UInt32             hdrlen = kEnetPacketHeaderLength;
  1112. T8022AddressStruct    *boundAddr;    
  1113.  
  1114. if (theStream->dlpiState != DL_UNBOUND) 
  1115.     {
  1116.     saplen = (theStream->streamFlags & kSnapStream) 
  1117.         ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength;
  1118.  
  1119.     if (theStream->dlsap == kSNAPSAP)     
  1120.         hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength;    // SNAP address 
  1121.     else if ((theStream->dlsap <= kMax8022SAP) || (theStream->dlsap == kIPXSAP))
  1122.         hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength;    // SAP or IPX 
  1123.     else                                
  1124.         hdrlen = kEnetPacketHeaderLength;    // basic Ethernet
  1125.     }
  1126.  
  1127. if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL)
  1128.     {
  1129.     DoWriteScheduler(theStream, sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen);
  1130.     return(kdlpiRETRY);
  1131.     }
  1132.  
  1133. ack_mp->b_datap->db_type = M_PCPROTO;
  1134. ackp = (dl_info_ack_t *)ack_mp->b_rptr;
  1135.  
  1136. if ( theStream->streamFlags & kReadRawPackets )
  1137.     ackp->dl_max_sdu = kEnetTSDU;        // for raw packet mode
  1138. else
  1139.     ackp->dl_max_sdu = kEnetTSDU - hdrlen;
  1140.  
  1141. ackp->dl_min_sdu = 1;
  1142. ackp->dl_addr_length = addrlen + saplen;
  1143. ackp->dl_mac_type = (gDLPIPrivateData->privateFlags & kpfFraming8022) ? DL_CSMACD : DL_ETHER;
  1144. ackp->dl_reserved = 0;
  1145. ackp->dl_sap_length = -saplen;        // negative to indicate sap follows physical address
  1146. ackp->dl_service_mode = DL_CLDLS;
  1147. ackp->dl_qos_length = 0;
  1148. ackp->dl_qos_offset = DL_UNKNOWN;
  1149. ackp->dl_qos_range_length = 0;
  1150. ackp->dl_qos_range_offset = DL_UNKNOWN;
  1151. ackp->dl_provider_style = DL_STYLE1;
  1152. ackp->dl_addr_offset = sizeof(dl_info_ack_t);
  1153. ackp->dl_version = DL_VERSION_2;
  1154. ackp->dl_brdcst_addr_length = bcastlen;
  1155. ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen;
  1156. ackp->dl_growth = 0;
  1157. ackp->dl_primitive = DL_INFO_ACK;
  1158. ackp->dl_current_state = theStream->dlpiState;
  1159. ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen;
  1160.  
  1161. boundAddr = ((T8022AddressStruct*)(ack_mp->b_rptr + ackp->dl_addr_offset));
  1162.  
  1163. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,boundAddr->fHWAddr);
  1164. if (saplen)
  1165.     {
  1166.     boundAddr->fSAP = theStream->dlsap;
  1167.     if (theStream->streamFlags & kSnapStream) 
  1168.         OTCopy8022SNAP(theStream->snap, boundAddr->fSNAP);
  1169.     }
  1170.     
  1171. OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset);    
  1172.  
  1173. putnext(theStream->readQueue, ack_mp);
  1174. return (kdlpiDONE);
  1175. }
  1176.  
  1177. //-----------------------------------------------------------------------------------------
  1178. //    Description:
  1179. //        This is a utility routine that compares to address (byte arrays).  
  1180. //
  1181. //    Input:
  1182. //        a - address array 1
  1183. //        b - address array 2
  1184. //        len - number of bytes that should match in the arrays
  1185. //
  1186. //    Output:
  1187. //        returns kTrue if they match and kFalse if they do not
  1188. //
  1189. //-----------------------------------------------------------------------------------------
  1190. Boolean CheckAddressMatch(UInt8 *a, UInt8 *b, SInt32 len)
  1191. {
  1192. register SInt32 i;
  1193.  
  1194. for (i = 0; i < len; i++) 
  1195.     {
  1196.     if (*a++ != *b++)
  1197.         return kFalse;
  1198.     }
  1199.  
  1200. return kTrue;
  1201. }
  1202.  
  1203. //-----------------------------------------------------------------------------------------
  1204. //    Description:
  1205. //        This routine fills in the ok ack message block and then passes it to the client.
  1206. //
  1207. //    Input:
  1208. //        theStream - the stream that will be passed the ok ack
  1209. //        ack_mp - ok ack message block
  1210. //        primitive - call that is being ack'd
  1211. //
  1212. //    Output:
  1213. //        NONE
  1214. //
  1215. //-----------------------------------------------------------------------------------------
  1216. void DoOKAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 primitive)
  1217. {
  1218. dl_ok_ack_t *ackp;
  1219.  
  1220. ack_mp->b_datap->db_type = M_PCPROTO;
  1221. ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
  1222. ackp = (dl_ok_ack_t *)ack_mp->b_wptr;
  1223. ackp->dl_primitive = DL_OK_ACK;
  1224. ackp->dl_correct_primitive = primitive;
  1225. ack_mp->b_wptr += sizeof(dl_ok_ack_t);
  1226. putnext(theStream->readQueue, ack_mp);
  1227. }
  1228.  
  1229. //-----------------------------------------------------------------------------------------
  1230. //    Description:
  1231. //        This routine acks the get physical address (ethernet) call from the client.
  1232. //        An ack message block is built and filled in.  If this message block cannot
  1233. //        be allocated then a scheduler task is queued.
  1234. //
  1235. //    Input:
  1236. //        theStream - the stream requesting the physical address information
  1237. //        mp - the message block requesting the physical address
  1238. //
  1239. //    Output:
  1240. //        returns status of the call
  1241. //
  1242. //-----------------------------------------------------------------------------------------
  1243. SInt32 DoPhysicalAddressAck(DLPIStream *theStream, mblk_t *mp) 
  1244. {
  1245. mblk_t                 *ack_mp;
  1246. dl_phys_addr_ack_t    *ackp;
  1247. dl_phys_addr_req_t     *addrReq = (dl_phys_addr_req_t *)mp->b_rptr;
  1248. UInt8                addressArray[kEnetPhysicalAddressLength];
  1249.  
  1250. if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) 
  1251.     {
  1252.     DoWriteScheduler(theStream, DL_PHYS_ADDR_ACK_SIZE + kEnetPhysicalAddressLength);
  1253.     return(kdlpiRETRY);
  1254.     }
  1255.     
  1256. ack_mp->b_datap->db_type = M_PCPROTO;
  1257. ackp = (dl_phys_addr_ack_t *)ack_mp->b_wptr;
  1258. ackp->dl_primitive = DL_PHYS_ADDR_ACK;
  1259. ackp->dl_addr_length = kEnetPhysicalAddressLength;
  1260. ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
  1261. ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength;
  1262. switch(addrReq->dl_addr_type)
  1263.     {
  1264.     case DL_CURR_PHYS_ADDR:
  1265.         OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress, 
  1266.             ack_mp->b_rptr + ackp->dl_addr_offset);
  1267.         break;
  1268.     case DL_FACT_PHYS_ADDR:
  1269.         ABCVendorGetFactoryEthernetAddress(addressArray);
  1270.         OTCopy48BitAddress(addressArray, ack_mp->b_rptr + ackp->dl_addr_offset);
  1271.         break;
  1272.     default:
  1273.         break;
  1274.     }
  1275.  
  1276. putnext(theStream->readQueue, ack_mp);
  1277. return(kdlpiDONE);
  1278. }
  1279.  
  1280. //-----------------------------------------------------------------------------------------
  1281. //    Description:
  1282. //        This routine is NOT finished yet.  The statistics will be returned through this
  1283. //        call, but the format of the structure(s) has not been determined.  The code
  1284. //        that calls this routine (WriteServiceRoutine) has been commented out so this
  1285. //        routine will never get called.  I added this routine so that it is a placeholder
  1286. //        for when the decision has been made on how to return the statistics.
  1287. //
  1288. //    Input:
  1289. //        theStream - the stream requesting the physical address information
  1290. //        mp - the message block requesting the statistics
  1291. //
  1292. //    Output:
  1293. //        returns status of the call
  1294. //
  1295. //-----------------------------------------------------------------------------------------
  1296. SInt32 DoStatisticsAck(DLPIStream *theStream, mblk_t *mp) 
  1297. {
  1298. mblk_t                     *ack_mp;
  1299. dl_get_statistics_ack_t    *statAckStruct;
  1300. UInt16                    statSize;
  1301.  
  1302. statSize = 100;        // this is not a valid number, just a number that lets us compile
  1303.  
  1304. if ((ack_mp = allocb(sizeof(dl_get_statistics_ack_t) + statSize, BPRI_HI)) == NULL) 
  1305.     {
  1306.     DoWriteScheduler(theStream, sizeof(dl_get_statistics_ack_t) + statSize);
  1307.     return(kdlpiRETRY);
  1308.     }
  1309.     
  1310. ack_mp->b_datap->db_type = M_PCPROTO;
  1311. statAckStruct = (dl_get_statistics_ack_t *)ack_mp->b_wptr;
  1312. statAckStruct->dl_primitive = DL_GET_STATISTICS_ACK;
  1313.  
  1314. statAckStruct->dl_stat_length = statSize;
  1315. statAckStruct->dl_stat_offset = sizeof(dl_get_statistics_ack_t);
  1316. ack_mp->b_wptr += sizeof(dl_get_statistics_ack_t) + statSize;
  1317.  
  1318.  
  1319. // WE NEED TO COPY OUR STATISTICS TO THE MESSAGE BLOCK
  1320.  
  1321.  
  1322. putnext(theStream->readQueue, ack_mp);
  1323. return(kdlpiDONE);
  1324.  
  1325. }
  1326.  
  1327. //-----------------------------------------------------------------------------------------
  1328. //    Description:
  1329. //        This routine accepts subsbind primitives.  A subsbind is used to register
  1330. //        802.2 SAP group addresses and snaps.  snaps can only be bound to a stream
  1331. //        that has a dlsap of 0xAA.
  1332. //
  1333. //            DL_PEER_BIND - for group addresses
  1334. //            DL_HIERARCHICAL_BIND - for additional snaps
  1335. //
  1336. //    Input:
  1337. //        theStream - the stream being bound
  1338. //        mp - the message block containing the subsbind parameters
  1339. //
  1340. //    Output:
  1341. //        returns status of the call
  1342. //
  1343. //-----------------------------------------------------------------------------------------
  1344. SInt32  SubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1345. {
  1346. dl_subs_bind_req_t     *req = (dl_subs_bind_req_t *)mp->b_rptr;
  1347. mblk_t                 *ack_mp;
  1348. UInt8                 *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
  1349. SInt32                 length = req->dl_subs_sap_length;
  1350. UInt16                 theSap;
  1351. SInt32                 error = kOTNoError;
  1352.  
  1353. if (theStream->dlpiState != DL_IDLE) 
  1354.     return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0));
  1355.  
  1356. theSap = *((UInt16 *)sap);
  1357.  
  1358. switch(req->dl_subs_bind_class)
  1359.     {
  1360.     case DL_PEER_BIND:
  1361.         if (theStream->dlsap <= kMax8022SAP) 
  1362.             {
  1363.             if ((theSap & 1) && (length == sizeof(theSap)))
  1364.                 SetGroupSAP(theStream, theSap);
  1365.             else
  1366.                 if (theSap == 0x0000)    // special case to receive all 802.2 packets
  1367.                     theStream->streamFlags |= kAcceptAll8022Packets;
  1368.                 else
  1369.                     error = DL_BADADDR;
  1370.             } 
  1371.         else
  1372.             error = DL_UNSUPPORTED;
  1373.         break;    
  1374.     
  1375.     case DL_HIERARCHICAL_BIND:    
  1376.         if (theStream->dlsap == kSNAPSAP)
  1377.             {
  1378.             if (theStream->streamFlags & kSnapStream) 
  1379.                 error = DL_TOOMANY;    // only one SNAP binding allowed 
  1380.             else
  1381.                 {
  1382.                 OTCopy8022SNAP(sap, theStream->snap);
  1383.                 theStream->streamFlags |= kSnapStream;
  1384.                 }
  1385.             }
  1386.         else
  1387.             error = DL_BADADDR;
  1388.         break;
  1389.         
  1390.     default:
  1391.         error = DL_UNSUPPORTED;
  1392.         break;
  1393.     }
  1394.     
  1395.  
  1396. if (error) 
  1397.     return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, error, 0));
  1398.  
  1399. if ((ack_mp = BuildSubsBindAck(theStream, sap, length)) == NULL)
  1400.     return (kdlpiRETRY);
  1401.  
  1402. freemsg(mp);
  1403. theStream->dlpiState = DL_IDLE;
  1404. putnext(theStream->readQueue, ack_mp);
  1405. return(kdlpiDONE);
  1406. }
  1407.  
  1408. //-----------------------------------------------------------------------------------------
  1409. //    Description:
  1410. //        This routine builds the ack for the subsbind call.  If the ack message block
  1411. //        cannot be scheduled then a task is queued.
  1412. //
  1413. //    Input:
  1414. //        theStream - the stream that will be sent the subsbind ack
  1415. //        sap - the sap to be returned in the ack mb
  1416. //        length - number of valid bytes in the sap
  1417. //
  1418. //    Output:
  1419. //        returns ack message block
  1420. //
  1421. //-----------------------------------------------------------------------------------------
  1422. mblk_t *BuildSubsBindAck(DLPIStream *theStream, UInt8 *sap, SInt32 length)
  1423. {
  1424. dl_subs_bind_ack_t    *ackp;
  1425. mblk_t                 *mp;
  1426.  
  1427. if ((mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) 
  1428.     {
  1429.     DoWriteScheduler(theStream, sizeof(dl_subs_bind_ack_t) + length);
  1430.     return(NULL);
  1431.     }
  1432.     
  1433. mp->b_datap->db_type = M_PCPROTO;
  1434. ackp = (dl_subs_bind_ack_t *)mp->b_wptr;
  1435. bzero(ackp, sizeof(dl_subs_bind_ack_t) + length);
  1436. ackp->dl_primitive = DL_SUBS_BIND_ACK;
  1437. ackp->dl_subs_sap_length = length;
  1438. ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0;
  1439. mp->b_wptr += sizeof(dl_subs_bind_ack_t);
  1440. if (length)
  1441.     bcopy(sap, mp->b_wptr, length);
  1442. mp->b_wptr += length;
  1443.  
  1444. return(mp);
  1445. }
  1446.  
  1447. //-----------------------------------------------------------------------------------------
  1448. //    Description:
  1449. //        This routine handles changing the Ethernet address of the card.  All streams 
  1450. //        opened on this port must be in the unbound state.  The address length must
  1451. //        be equal to the Ethernet physical length.
  1452. //
  1453. //    Input:
  1454. //        theStream - the stream requesting the new physical address
  1455. //        mp - the message block containing the physical address
  1456. //
  1457. //    Output:
  1458. //        returns status of the call
  1459. //
  1460. //-----------------------------------------------------------------------------------------
  1461. SInt32 DoSetPhysicalAddress(DLPIStream *theStream, mblk_t *mp)
  1462. {
  1463. dl_set_phys_addr_req_t     *req = (dl_set_phys_addr_req_t *)mp->b_rptr;
  1464. SInt32                     length = req->dl_addr_length;
  1465. mblk_t                     *ack_mp;
  1466. UInt8                    *physicalAddress = ((UInt8 *)req) + req->dl_addr_offset;
  1467.  
  1468.  
  1469. if (!AreAllStreamsUnbound())         // all streams must be unbound, if error abort
  1470.     {
  1471.     if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1472.         return(kdlpiRETRY);
  1473.     freemsg(mp);
  1474.     return(kdlpiDONE);
  1475.     }
  1476.  
  1477. if (length != kEnetPhysicalAddressLength)     // must only contain Ethernet address
  1478.     {
  1479.     if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0) == kdlpiRETRY)
  1480.         return(kdlpiRETRY);
  1481.     freemsg(mp);
  1482.     return(kdlpiDONE);
  1483.     }
  1484.     
  1485. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1486.     {
  1487.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1488.     return(kdlpiRETRY);
  1489.     }
  1490.  
  1491. ABCVendorSetEthernetAddress(physicalAddress);
  1492.  
  1493. freemsg(mp);
  1494.  
  1495. DoOKAck(theStream, ack_mp, DL_SET_PHYS_ADDR_REQ);
  1496.     
  1497. return(kdlpiDONE);
  1498. }
  1499.  
  1500. //-----------------------------------------------------------------------------------------
  1501. //    Description:
  1502. //        This routine handles the unsubsbind primitive/call.  A snap can be unbound and
  1503. //        also a 802.2 group address.  An ok ack message block is sent to the client
  1504. //        if everything goes well and error ack if not.
  1505. //
  1506. //    Input:
  1507. //        theStream - the stream requesting the unsubsbind
  1508. //        mp - the message block containing the unsubsbind parameters
  1509. //
  1510. //    Output:
  1511. //        returns status of the call
  1512. //
  1513. //-----------------------------------------------------------------------------------------
  1514. SInt32 UnSubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1515. {
  1516. dl_subs_unbind_req_t     *req = (dl_subs_unbind_req_t *)mp->b_rptr;
  1517. UInt8                     *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
  1518. SInt32                     length = req->dl_subs_sap_length;
  1519. mblk_t                     *ack_mp;
  1520. SInt32                     error = 0;
  1521.  
  1522. if (theStream->dlpiState != DL_IDLE) 
  1523.     {
  1524.     if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1525.         return(kdlpiRETRY);
  1526.     freemsg(mp);
  1527.     return(kdlpiDONE);
  1528.     }
  1529.     
  1530. if (length == k8022SAPLength) 
  1531.     {
  1532.     if ((*sap & 1) && (*sap != kIPXSAP)) 
  1533.         {
  1534.         if (theStream->dlsap <= kMax8022SAP)
  1535.             ClearGroupSAP(theStream, *sap);
  1536.         else
  1537.             error = DL_UNSUPPORTED;
  1538.         } 
  1539.     else
  1540.         error = DL_BADADDR;
  1541.     } 
  1542. else 
  1543.     if (length == k8022SNAPLength) 
  1544.     {
  1545.     if (theStream->dlsap == kSNAPSAP) 
  1546.         {
  1547.         if (theStream->streamFlags & kSnapStream) 
  1548.             {
  1549.             if (CheckAddressMatch(theStream->snap, sap, length) == kFalse) 
  1550.                 error = DL_BADADDR;
  1551.             } 
  1552.         else
  1553.             error = DL_BADADDR;
  1554.         } 
  1555.     else
  1556.         error = DL_UNSUPPORTED;
  1557.     }
  1558.  
  1559. if (error) 
  1560.     {
  1561.     if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, error, 0) == kdlpiRETRY)
  1562.         return(kdlpiRETRY);
  1563.     freemsg(mp);
  1564.     return(kdlpiDONE);
  1565.     }
  1566.     
  1567. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1568.     {
  1569.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1570.     return(kdlpiRETRY);
  1571.     }
  1572.     
  1573. freemsg(mp);
  1574. theStream->streamFlags &= ~kSnapStream;
  1575. DoOKAck(theStream, ack_mp, DL_SUBS_UNBIND_REQ);
  1576.  
  1577. return(kdlpiDONE);
  1578. }
  1579.  
  1580. //-----------------------------------------------------------------------------------------
  1581. //    Description:
  1582. //        This routine if called when the client wishes to unbind the stream.  An ok ack is
  1583. //        sent to the client if everything goes well.
  1584. //
  1585. //    Input:
  1586. //        theStream - the stream being unbound
  1587. //        mp - the message block containing the unbind message
  1588. //
  1589. //    Output:
  1590. //        returns status of the call
  1591. //
  1592. //-----------------------------------------------------------------------------------------
  1593. SInt32 UnBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1594. {
  1595. mblk_t *ack_mp;
  1596.  
  1597. if (theStream->dlpiState != DL_IDLE) 
  1598.     {
  1599.     if (DoErrorAck(theStream, 0, DL_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1600.         return(kdlpiRETRY);
  1601.     freemsg(mp);
  1602.     return(kdlpiDONE);
  1603.     }
  1604.  
  1605. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1606.     {
  1607.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1608.     return(kdlpiRETRY);
  1609.     }
  1610.     
  1611. freemsg(mp);
  1612.  
  1613. //if (putctl1(theStream->readQueue->q_next, M_FLUSH, FLUSHRW) == 0)
  1614.  
  1615. theStream->dlpiState = DL_UNBOUND;
  1616. theStream->dlsap = 0;                
  1617. DoOKAck(theStream, ack_mp, DL_UNBIND_REQ);
  1618. return(kdlpiDONE);
  1619. }
  1620.  
  1621. //-----------------------------------------------------------------------------------------
  1622. //    Description:
  1623. //        This utility routine sets a bit in the group sap array that indicates if a 
  1624. //        certain group sap has been bound (subsbind).
  1625. //
  1626. //    Input:
  1627. //        theStream - the stream for the group sap
  1628. //        sap - group sap that needs registration bit set
  1629. //
  1630. //    Output:
  1631. //        NONE
  1632. //
  1633. //-----------------------------------------------------------------------------------------
  1634. void SetGroupSAP(DLPIStream *theStream, UInt8 sap) 
  1635. {
  1636. theStream->group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask));
  1637. }
  1638.  
  1639. //-----------------------------------------------------------------------------------------
  1640. //    Description:
  1641. //        This utility routine is used to clear a registration bit for a certain sap.
  1642. //
  1643. //    Input:
  1644. //        theStream - the stream for the group sap
  1645. //        sap - group sap that needs registration bit cleared
  1646. //
  1647. //    Output:
  1648. //        NONE
  1649. //
  1650. //-----------------------------------------------------------------------------------------
  1651. void ClearGroupSAP(DLPIStream *theStream, UInt8 sap)
  1652. {
  1653. theStream->group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask));
  1654. }
  1655.  
  1656. //-----------------------------------------------------------------------------------------
  1657. //    Description:
  1658. //        This utility routine tests a registration bit against a sap.  
  1659. //
  1660. //    Input:
  1661. //        theStream - the stream for the group sap
  1662. //        sap - group sap that needs checking
  1663. //
  1664. //    Output:
  1665. //        returns kTrue is sap is registered, kFalse if not
  1666. //
  1667. //-----------------------------------------------------------------------------------------
  1668. Boolean TestGroupSAP(DLPIStream *theStream, UInt8 sap) 
  1669. {
  1670. return 0 != (theStream->group_sap[sap >> kGSshift] & (1L << ((sap >> 1) & kGSmask)));
  1671. }
  1672.  
  1673. //-----------------------------------------------------------------------------------------
  1674. //    Description:
  1675. //        This routine builds the uderror message block and sends it to the stream's client.
  1676. //
  1677. //    Input:
  1678. //        theStream - the stream sending the message block
  1679. //        dest - the destination address
  1680. //        destlen - number of bytes valid in dest parameter
  1681. //        err - error to retrun in the message block
  1682. //        uerr - unix error returned in the message block
  1683. //
  1684. //    Output:
  1685. //        NONE
  1686. //
  1687. //-----------------------------------------------------------------------------------------
  1688. void DoUdError(DLPIStream *theStream, UInt8 *dest, UInt32 destlen, UInt32 err, 
  1689.      UInt32 uerr)
  1690. {
  1691. dl_uderror_ind_t    *errp;
  1692. mblk_t                 *bp;
  1693. SInt32                 i;
  1694.  
  1695. i = sizeof(dl_uderror_ind_t) + destlen;
  1696. if ((bp = allocb(i, BPRI_HI)) == NULL)
  1697.     return;
  1698. bp->b_datap->db_type = M_PROTO;
  1699. errp = (dl_uderror_ind_t *)bp->b_wptr;
  1700. errp->dl_primitive = DL_UDERROR_IND;
  1701. errp->dl_errno = err;
  1702. errp->dl_unix_errno = uerr;
  1703. errp->dl_dest_addr_length = destlen;
  1704. errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
  1705. bp->b_wptr += sizeof(dl_uderror_ind_t);
  1706. bcopy((UInt8 *)dest, (UInt8 *)bp->b_wptr, destlen);
  1707. bp->b_wptr += destlen;
  1708. putnext(theStream->readQueue, bp);
  1709. }
  1710.  
  1711. //-----------------------------------------------------------------------------------------
  1712. //    Description:
  1713. //        This routine is called when someone cannot allocate a message block for an ok ack
  1714. //        or error ack.  This routine says call me when you have enough memory for my
  1715. //        message block.
  1716. //
  1717. //    Input:
  1718. //        theStream - the stream to disable until memory is available
  1719. //        size - number of bytes needed for the message block
  1720. //
  1721. //    Output:
  1722. //        NONE
  1723. //
  1724. //-----------------------------------------------------------------------------------------
  1725. void DoWriteScheduler(DLPIStream *theStream, SInt32 size)
  1726. {
  1727.  
  1728. theStream->timeoutID = bufcall(size, BPRI_HI, EnableWriteQueue, (SInt32)theStream);
  1729. if (theStream->timeoutID) 
  1730.     theStream->idType = kdlpiBufcallType;
  1731. else 
  1732.     if ((*((UInt32 *)theStream->bufferTimerMsg->b_rptr)) == NULL)    // is timer unused?
  1733.         {
  1734.         *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = kEnableQueueTimerMsg;
  1735.         mi_timer(theStream->bufferTimerMsg,500);    // send us a timer message in 1/2 sec
  1736.         }
  1737. }
  1738.  
  1739. //-----------------------------------------------------------------------------------------
  1740. //    Description:
  1741. //        This routine checks if all the streams are in the unbound state.
  1742. //
  1743. //    Input:
  1744. //        NONE
  1745. //
  1746. //    Output:
  1747. //        kTrue, if all the streams are unbound
  1748. //        kFalse, if some stream is not in the unbound state
  1749. //
  1750. //-----------------------------------------------------------------------------------------
  1751.  
  1752. Boolean AreAllStreamsUnbound(void)
  1753. {
  1754. mblk_t    *mbWalker;
  1755. Boolean    unbound = kTrue;
  1756.  
  1757. mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  1758.  
  1759. while (mbWalker && unbound) 
  1760.     {
  1761.     if (((DLPIStream *)mbWalker)->dlpiState == DL_UNBOUND)
  1762.         mbWalker = mbWalker->b_next;
  1763.     else
  1764.         unbound = kFalse;
  1765.     }
  1766.     
  1767. return unbound;
  1768. }
  1769.  
  1770. //-----------------------------------------------------------------------------------------
  1771. //    Description:
  1772. //        This routine processes a message block that contains a packet that needs to
  1773. //        be transmitted over the wire.  Error ack message blocks are sent to the
  1774. //        client if errors appear during processing.
  1775. //
  1776. //    Input:
  1777. //        theStream - the stream requesting the packet transmission
  1778. //        mp - the message block containing the packet
  1779. //
  1780. //    Output:
  1781. //        NONE
  1782. //
  1783. //-----------------------------------------------------------------------------------------
  1784. void DoUnitData(DLPIStream *theStream, mblk_t *mp)
  1785. {
  1786.  
  1787. dl_unitdata_req_t*    req;
  1788.  
  1789. req = (dl_unitdata_req_t *)mp->b_rptr;
  1790.  
  1791. if (theStream->dlpiState != DL_IDLE) 
  1792.     {
  1793.     DoUdError(theStream, ((UInt8 *)req) +  req->dl_dest_addr_offset, 
  1794.         req->dl_dest_addr_length, DL_OUTSTATE, 0);
  1795.     freemsg(mp);
  1796.     return;
  1797.     }
  1798.     
  1799. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1800.     PreparePacketToBeSent(mp);
  1801.     
  1802. }
  1803.  
  1804. //-----------------------------------------------------------------------------------------
  1805. //    Description:
  1806. //        This routine sends Test requests and responses.  The test primitives are only
  1807. //        valid on 802.2 streams.  A request packet should not be sent if the client
  1808. //        requested auto handling of the test messages.
  1809. //
  1810. //    Input:
  1811. //        theStream - the stream that wants to send the test
  1812. //        mp - message block that contains the data to send
  1813. //        requestFlag - kTrue if mp is a test request, kFalse if mp is a test response
  1814. //
  1815. //    Output:
  1816. //        NONE
  1817. //
  1818. //-----------------------------------------------------------------------------------------
  1819. SInt32 SendTestPacket(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
  1820. {                
  1821. Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
  1822.  
  1823. if (!is8022)
  1824.     {
  1825.     freemsg(mp);
  1826.     return kdlpiDONE;
  1827.     }
  1828.  
  1829. if (requestFlag && (theStream->streamFlags & kAutoTest))
  1830.     return( DoErrorAck(theStream, mp, DL_TEST_REQ, DL_TESTAUTO, 0));
  1831.  
  1832. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1833.     PreparePacketToBeSent(mp);
  1834.     
  1835. return kdlpiDONE;
  1836. }
  1837.  
  1838. //-----------------------------------------------------------------------------------------
  1839. //    Description:
  1840. //        This routine sends XID requests and responses.  The XID primitives are only
  1841. //        valid on 802.2 streams.  A request packet should not be sent if the client
  1842. //        requested auto handling of the XID messages.
  1843. //
  1844. //    Input:
  1845. //        theStream - the stream that wants to send the XID
  1846. //        mp - message block that contains the data to send
  1847. //        requestFlag - kTrue if mp is a XID request, kFalse if mp is a XID response
  1848. //
  1849. //    Output:
  1850. //        NONE
  1851. //
  1852. //-----------------------------------------------------------------------------------------
  1853. SInt32 DoXID(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
  1854. {                
  1855. Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
  1856.  
  1857. if (!is8022)
  1858.     {
  1859.     freemsg(mp);
  1860.     return kdlpiDONE;
  1861.     }
  1862.  
  1863. if (requestFlag && (theStream->streamFlags & kAutoTest))
  1864.     return( DoErrorAck(theStream, mp, DL_XID_REQ, DL_XIDAUTO, 0));
  1865.  
  1866. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1867.     PreparePacketToBeSent(mp);
  1868.  
  1869. return kdlpiDONE;
  1870. }
  1871.  
  1872. //-----------------------------------------------------------------------------------------
  1873. //    Description:
  1874. //         This routine builds the header block for Test/XID Indication/confirm packets.
  1875. //        So this routine can receive 4 types of packets for which it must build
  1876. //        a correct header so that the entire message can be passed up to our client.
  1877. //
  1878. //        The headers for each of the different types of packets is exactly the
  1879. //        same so we will just us the test indication structure for all the packet
  1880. //        types.
  1881. //
  1882. //    Input:
  1883. //        mp - message block that contains the info for building a test message
  1884. //        dlsap_length - the number of bytes in the mp message block 
  1885. //
  1886. //    Output:
  1887. //        NONE
  1888. //
  1889. //-----------------------------------------------------------------------------------------
  1890. void    BuildXidTestConfirmIndication(DLPIStream *theStream, mblk_t *mp, 
  1891.         UInt16 destAddrLength, UInt16 headerHideLength)
  1892. {
  1893. UInt32             primitive;
  1894. mblk_t             *nmp;
  1895. dl_test_ind_t*     ind;
  1896. UInt8             ssap = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP;
  1897. UInt8             ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
  1898. T8022FullPacketHeader    *packetHeader;
  1899. T8022AddressStruct        *srcAddr,*destAddr;
  1900.  
  1901. if ((ctrl & 0xEF) == 0xE3)
  1902.     primitive = (ssap & 1) ? DL_TEST_CON : DL_TEST_IND;
  1903. else if ((ctrl & 0xEF) == 0xAF)
  1904.     primitive = (ssap & 1) ? DL_XID_CON : DL_XID_IND;
  1905. else
  1906.     return;
  1907.  
  1908.     //    Allocate a dl_test_(ind,con,xid)_t message, and fill it in.
  1909. if ((nmp = allocb(sizeof(dl_test_ind_t) + (destAddrLength * 2), BPRI_HI)) == NULL)
  1910.     {
  1911.     freemsg(mp);
  1912.     return;
  1913.     }
  1914.     
  1915. nmp->b_datap->db_type = M_PROTO;
  1916. ind = (dl_test_ind_t*)nmp->b_rptr;
  1917. ind->dl_primitive = primitive;
  1918. ind->dl_flag = (ctrl & 0x10) ? DL_POLL_FINAL : 0;
  1919. ind->dl_dest_addr_length = destAddrLength;
  1920. ind->dl_dest_addr_offset = sizeof(dl_test_ind_t);
  1921. ind->dl_src_addr_length = destAddrLength;
  1922. ind->dl_src_addr_offset = sizeof(dl_test_ind_t) + destAddrLength;
  1923. nmp->b_wptr += (sizeof(dl_test_ind_t) + destAddrLength + destAddrLength);
  1924.  
  1925. packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
  1926.  
  1927. destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
  1928. srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
  1929.  
  1930. BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
  1931.  
  1932. mp->b_rptr += headerHideLength;    // "hide" the ethernet and protocol header(s) 
  1933.  
  1934.     // Append data to M_PROTO IND/TEST/XID block & pass it on to the client stream.
  1935. linkb(nmp, mp);
  1936. putnext(theStream->readQueue, nmp);        // pass the message up the stream
  1937. return;
  1938.  
  1939. }
  1940.  
  1941. //-----------------------------------------------------------------------------------------
  1942. //    Description:
  1943. //        This routine sends a test response packet that was created from the test request
  1944. //        that was received.  When auto handling is turned on during the bind, the dlpi
  1945. //        sends test responses when it receives a test request.
  1946. //
  1947. //        To send the response a control message block is built from the information in 
  1948. //        the received packet.  The Ethernet and protocol is then hidden in the original
  1949. //        request message block.  The two blocks are then linked together and passed to
  1950. //        the send unit data routine.
  1951. //
  1952. //    Input:
  1953. //        theStream - the stream sending the test reponse
  1954. //        mp - the message block containing the test request
  1955. //
  1956. //    Output:
  1957. //        NONE
  1958. //
  1959. //-----------------------------------------------------------------------------------------
  1960. void DoTestResponse(DLPIStream *theStream, mblk_t *mp)
  1961. {
  1962. T8022FullPacketHeader     *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
  1963. Boolean                 isSnap;
  1964. UInt32                     destAddrLength;
  1965. UInt32                     headerHideCount;
  1966. mblk_t                     *nmp;
  1967. dl_test_res_t             *responseStruct;
  1968. T8022AddressStruct         *destAddrTemplate;
  1969.  
  1970.     // since test is only valid for 802.2 we start we the basic values
  1971. destAddrLength = kEnetAndSAPAddressLength;
  1972. headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  1973. isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
  1974.  
  1975. if (isSnap) 
  1976.     {
  1977.     destAddrLength += k8022SNAPLength;
  1978.     headerHideCount += k8022SNAPLength;
  1979.     }
  1980.  
  1981.     // Allocate the dl_test_res_t message, and fill it in
  1982. if ((nmp = allocb(sizeof(dl_test_res_t) + destAddrLength, BPRI_HI)) == NULL) 
  1983.     {
  1984.     freemsg(mp);
  1985.     return;
  1986.     }
  1987.     
  1988. nmp->b_datap->db_type = M_PROTO;
  1989.  
  1990. responseStruct = (dl_test_res_t *)nmp->b_rptr;
  1991. responseStruct->dl_primitive = DL_TEST_RES;
  1992. responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
  1993. responseStruct->dl_dest_addr_length = destAddrLength;
  1994. responseStruct->dl_dest_addr_offset = sizeof(dl_test_res_t);
  1995.  
  1996. nmp->b_wptr += sizeof(dl_test_res_t);
  1997. destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
  1998.  
  1999. OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
  2000. destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
  2001.  
  2002. if (isSnap)
  2003.     OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
  2004.  
  2005. nmp->b_wptr += destAddrLength;
  2006. mp->b_rptr += headerHideCount;
  2007.  
  2008. linkb(nmp, mp);
  2009.  
  2010. DoUnitData(theStream, nmp);
  2011.  
  2012. }
  2013.  
  2014. //-----------------------------------------------------------------------------------------
  2015. //    Description:
  2016. //        This routine sends a xid response packet that was created from the xid request
  2017. //        that was received.  When auto handling is turned on during the bind, the dlpi
  2018. //        sends xid responses when it receives a xid request.
  2019. //
  2020. //        To send the response a control message block is built from the information in 
  2021. //        the received packet.  The Ethernet and protocol header is then hidden in the original
  2022. //        request message block.  The two blocks are then linked together and passed to
  2023. //        the send unit data routine.
  2024. //
  2025. //    Input:
  2026. //        theStream - the stream generating the xid response
  2027. //        mp - the message block containing the xid request message
  2028. //
  2029. //    Output:
  2030. //        NONE
  2031. //
  2032. //-----------------------------------------------------------------------------------------
  2033. void DoXidResponse(DLPIStream *theStream, mblk_t *mp)
  2034. {
  2035. T8022FullPacketHeader     *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
  2036. Boolean                 isSnap;
  2037. UInt32                     destAddrLength;
  2038. UInt32                     headerHideCount;
  2039. mblk_t                     *nmp;
  2040. dl_xid_res_t             *responseStruct;
  2041. T8022AddressStruct         *destAddrTemplate;
  2042.  
  2043.     // since xid is only valid for 802.2 we start we the basic values
  2044. destAddrLength = kEnetAndSAPAddressLength;
  2045. headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  2046. isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
  2047.  
  2048. if (isSnap) 
  2049.     {
  2050.     destAddrLength += k8022SNAPLength;
  2051.     headerHideCount += k8022SNAPLength;
  2052.     }
  2053.  
  2054.     // Allocate the dl_xid_res_t message, and fill it in
  2055. if ((nmp = allocb(sizeof(dl_xid_res_t) + destAddrLength, BPRI_HI)) == NULL) 
  2056.     {
  2057.     freemsg(mp);
  2058.     return;
  2059.     }
  2060.     
  2061. nmp->b_datap->db_type = M_PROTO;
  2062.  
  2063. responseStruct = (dl_xid_res_t *)nmp->b_rptr;
  2064. responseStruct->dl_primitive = DL_XID_RES;
  2065. responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
  2066. responseStruct->dl_dest_addr_length = destAddrLength;
  2067. responseStruct->dl_dest_addr_offset = sizeof(dl_xid_res_t);
  2068.  
  2069. nmp->b_wptr += sizeof(dl_xid_res_t);
  2070. destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
  2071.  
  2072. OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
  2073. destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
  2074.  
  2075. if (isSnap)
  2076.     OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
  2077.  
  2078. nmp->b_wptr += destAddrLength;
  2079. mp->b_rptr += headerHideCount;    // hide the ethernet and protocol headers
  2080.  
  2081. AddXIDInfoToPacketData(theStream,nmp, mp);        // send packet after adding xid info
  2082.  
  2083. }
  2084.  
  2085. //-----------------------------------------------------------------------------------------
  2086. //    Description:
  2087. //        This routine trys to add some xid information to the start of the packet
  2088. //        data.  Before we can modify the data we must make sure that the message
  2089. //        is not being used by anyone else.  If that is kTrue then we "backup" the
  2090. //        read pointer by 3 bytes and place the xid info at the beginning.
  2091. //
  2092. //        If the message is being used by someone else then an attempt to copy it is made.
  2093. //        If that goes okay then the original message is no longer needed so we free it.
  2094. //
  2095. //    Input:
  2096. //        theStream - the stream generating the xid response
  2097. //        mp - the message block containing the xid request message
  2098. //
  2099. //    Output:
  2100. //        NONE
  2101. //
  2102. //-----------------------------------------------------------------------------------------
  2103. void AddXIDInfoToPacketData(DLPIStream *theStream, mblk_t *headerMB, mblk_t *dataMB)
  2104. {
  2105. mblk_t    *theMB;
  2106.  
  2107. if (dataMB->b_datap->db_ref != 1)    // is anybody else using this message data
  2108.     {
  2109.     if ((theMB = copymsg(dataMB)) == NULL)    // try to make a copy of the message
  2110.         {
  2111.         freemsg(headerMB);    // could not make copy so lets just drop the packet
  2112.         freemsg(dataMB);
  2113.         return;
  2114.         }
  2115.     else
  2116.         {
  2117.         freemsg(dataMB);    // free the original
  2118.         dataMB = theMB;
  2119.         }
  2120.     }
  2121.  
  2122.  
  2123. dataMB->b_rptr -= 3;    // need to prepend xid response information before data
  2124.  
  2125.     // this xid response information can be found in the 802.2 spec., p. 52
  2126. dataMB->b_rptr[0] = 0x81;    // XID Format Identifier, IEEE Basic Format
  2127. dataMB->b_rptr[1] = 0x01;    // Type 1 LLC
  2128. dataMB->b_rptr[2] = 0x00;    // Receive window size, we now default to 0
  2129.  
  2130. linkb(headerMB, dataMB);
  2131. DoUnitData(theStream, headerMB);    
  2132.  
  2133. }
  2134.  
  2135.  
  2136.  
  2137.